package network.t_03_aio;

import lombok.AllArgsConstructor;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.nio.charset.StandardCharsets;

public class AIOClient {
    public static void main(String[] args) {
        try (AsynchronousSocketChannel asynchronousSocketChannel = AsynchronousSocketChannel.open()) {
            asynchronousSocketChannel.connect(new InetSocketAddress("127.0.0.1", 6666), null, new CompletionHandler<Void, Object>() {
                @Override
                public void completed(Void result, Object attachment) {
                    StringBuilder sb = new StringBuilder();
                    for (int i = 0; i <= 9999999; i++) sb.append("Hello：").append(i).append("，");
                    ByteBuffer buffer = ByteBuffer.allocate(4 + sb.toString().getBytes(StandardCharsets.UTF_8).length);
                    buffer.putInt(sb.toString().getBytes(StandardCharsets.UTF_8).length);
                    buffer.put(sb.toString().getBytes(StandardCharsets.UTF_8));
                    buffer.flip();
                    asynchronousSocketChannel.write(buffer, buffer, new WriteCompletionHandler(asynchronousSocketChannel));
                }

                @Override
                public void failed(Throwable exc, Object attachment) {
                    exc.printStackTrace();
                }
            });
            System.in.read();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @AllArgsConstructor
    static class ReadHeaderCompletionHandler implements CompletionHandler<Integer, ByteBuffer> {
        final AsynchronousSocketChannel clientChannel;

        @Override
        public void completed(Integer bytesRead, ByteBuffer buffer) {
            if (buffer.hasRemaining()) {
                clientChannel.read(buffer, buffer, this);
            } else {
                buffer.flip();
                ByteBuffer messageBuffer = ByteBuffer.allocate(buffer.getInt());
                clientChannel.read(messageBuffer, messageBuffer, new ReadMessageCompletionHandler(clientChannel));
            }
        }

        @Override
        public void failed(Throwable exc, ByteBuffer attachment) {
            exc.printStackTrace();
        }
    }

    @AllArgsConstructor
    private static class ReadMessageCompletionHandler implements CompletionHandler<Integer, ByteBuffer> {
        final AsynchronousSocketChannel clientChannel;

        @Override
        public void completed(Integer bytesRead, ByteBuffer buffer) {
            if (buffer.hasRemaining()) {
                clientChannel.read(buffer, buffer, this);
            } else {
                buffer.flip();
                byte[] bytes = new byte[buffer.remaining()];
                buffer.get(bytes);
                System.out.println(new String(bytes, StandardCharsets.UTF_8) + "\n收到数据");
            }
        }

        @Override
        public void failed(Throwable exc, ByteBuffer attachment) {
            exc.printStackTrace();
        }
    }

    @AllArgsConstructor
    static class WriteCompletionHandler implements CompletionHandler<Integer, ByteBuffer> {
        final AsynchronousSocketChannel clientChannel;

        @Override
        public void completed(Integer bytesWritten, ByteBuffer buffer) {
            if (buffer.hasRemaining()) clientChannel.write(buffer, buffer, this);
            else {
                System.out.println("发送完毕");
                ByteBuffer headBuffer = ByteBuffer.allocate(4);
                clientChannel.read(headBuffer, headBuffer, new ReadHeaderCompletionHandler(clientChannel));
            }
        }

        @Override
        public void failed(Throwable exc, ByteBuffer attachment) {
            exc.printStackTrace();
        }
    }
}